// main
package main

import (
	"fmt"
	"image"
	_ "image/gif"
	"image/jpeg"
	_ "image/png"
	"io"
	"io/ioutil"
	"math/rand"
	"net/http"
	"net/url"
	"strings"
	//	"net/url"
	"os"
	"strconv"
	"time"

	"github.com/labstack/echo"
	"github.com/nfnt/resize"
	"github.com/labstack/echo/middleware"
)

type JsonResp struct {
	Code     string `json:"code"`
	Data     string `json:"data"`
	Filename string `json:"filename"`
}

func main() {
	fmt.Println("Hello World!")
	e := echo.New()
	e.GET("/u/*", webPage)
	e.POST("/upload/*", uploadFile)
	e.GET("/upload/*", getUploadFile)
	e.GET("/thumb/*", getPicThumb)
	e.GET("/delete/*", deleteFile)
	e.POST("/mkdir/*", makeDirectory)
	e.Static("/assets", "assets")
	e.Use(middleware.BasicAuth(func(username, password string, c echo.Context) (bool, error) {
		if username == "username" && password == "password" {
			return true, nil
		}
		return false, nil
	}))
	e.Start(":8086")
}

func makeDirectory(c echo.Context) error {
	path, _ := url.QueryUnescape(c.Request().URL.String())
	path = path[6:]
	dirname := c.FormValue("dirname")
	fmt.Println(path + dirname)
	if !fileIsExisted("assets" + path + dirname) {
		os.Mkdir("assets"+path+dirname, 666)
	} else {
		return c.String(http.StatusInternalServerError, "Already existed.")
	}
	return c.Redirect(http.StatusMovedPermanently, "/u"+path)
}

func deleteFile(c echo.Context) error {
	path, _ := url.QueryUnescape(c.Request().URL.String())

	path = path[7:]
	if fileIsExisted("assets" + path) {
		f, err := os.Stat("assets" + path)
		if err != nil {
			return c.String(http.StatusInternalServerError, "An error occured.")
		}
		if !f.IsDir() {
			err = os.Rename("assets"+path, "recyclebin"+path[strings.LastIndex(path, "/"):])
			if err != nil {
				return c.String(http.StatusInternalServerError, "Failed.")
			}
		} else {
			return c.String(http.StatusInternalServerError, "Cannot delete directory.")
		}
	} else {
		return c.String(http.StatusInternalServerError, "Cannot find the file.")
	}
	//fmt.Println(path)
	return c.Redirect(http.StatusMovedPermanently, "/u"+path)
}

func LoadImage(path string) (img image.Image, err error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}

	defer file.Close()
	img, _, err = image.Decode(file) //解码图片
	return
}

func fileIsExisted(filename string) bool {
	_, err := os.Stat(filename)
	return err == nil || os.IsExist(err)
}

func isImageSuffix(filename string) bool {
	suffix := []string{
		"png",
		"jpg",
		"jpeg",
		"gif",
	}
	filename = strings.ToLower(filename)
	for _, s := range suffix {
		if strings.HasSuffix(filename, s) {
			return true
		}
	}
	return false
}

func getPicThumb(c echo.Context) error {
	path, err := url.QueryUnescape(c.Request().URL.String())

	path = path[6:]
	//fmt.Println(path)
	if !fileIsExisted("assets" + path) {
		return c.String(http.StatusInternalServerError, "Cannot find the image!")
	}
	if fileIsExisted("thumb" + path) {
		return c.File("thumb" + path)
	}

	if !isImageSuffix(path) {
		return c.File("thumb/null.png")
	}

	src, err := LoadImage("assets" + path)
	if err != nil {
		return c.String(http.StatusInternalServerError, "Loadimage err!")
	}
	dst := resize.Thumbnail(100, 60, src, resize.Lanczos3)
	picdir := path[:strings.LastIndex(path, "/")]
	if !fileIsExisted("thumb" + picdir) {
		os.Mkdir("thumb"+picdir, 777)
	}
	out, err := os.Create("thumb" + path)
	if err != nil {
		c.String(http.StatusInternalServerError, "Create err!")
	}
	defer out.Close()

	jpeg.Encode(out, dst, &jpeg.Options{70})
	return c.File("thumb" + path)
}

func webPage(c echo.Context) error {
	var output string
	path := c.Request().URL.String()
	path = path[2:]
	dir, err := ioutil.ReadDir("assets" + path)
	if err != nil {
		return c.String(http.StatusInternalServerError, "PAGE NOT FOUND!")
	}
	output += html_1_1 + path + html_1_2
	if path != "/" {
		output += `	    <tr>
	      <td><a href="../">返回上级../</a></td>
	      <td></td>
		  <td></td>
	    </tr>`
	}
	for _, f := range dir {
		if f.IsDir() {
			output += `	    <tr>
	      <td>` + `<a href="/u` + path + f.Name() + "/" + `">` + f.Name() + "/" + `</a>` + `</td>
	      <td></td>
		  <td></td>
	    </tr>`
		}
	}
	for _, f := range dir {
		if !f.IsDir() {
			output += `	    <tr>
	      <td>` + `<a href="/assets` + path + f.Name() + `">` + f.Name() + `</a>` + `</td>
	      <td>` + strconv.FormatFloat(float64(f.Size())/1024, 'f', 2, 32) + ` KB</td>
		  <td><img src="/thumb` + path + f.Name() + `" /></td>
		  <td>	
	     	<div class="btn-group">
			<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"> 选择 <span class="caret"></span>
			</button>
			<ul class="dropdown-menu" role="menu">
				<li><a href="/delete` + path + f.Name() + `">删除</a></li>
			</ul>
			</div>
		  </td>
	    </tr>`
		}
	}
	output += html_2 + "/upload" + path + html_3
	return c.HTML(http.StatusOK, output)
}

func getUploadFile(c echo.Context) error {
	path := c.Request().URL.String()
	path = path[7:]
	return c.String(http.StatusOK, path)
}

func uploadFile(c echo.Context) error {
	path := c.Request().URL.String()
	path = path[7:]
	file, err := c.FormFile("file")
	if err != nil {
		resp := &JsonResp{
			Code: "fileerror",
			Data: "Read form file failed.",
		}
		return c.JSON(http.StatusInternalServerError, resp)
	}
	src, err := file.Open()
	if err != nil {
		resp := &JsonResp{
			Code: "fileerror",
			Data: "Open file failed.",
		}
		return c.JSON(http.StatusInternalServerError, resp)
	}
	defer src.Close()

	var dst *os.File
	if fileIsExisted("assets" + path + "/" + file.Filename) {
		dst, err = os.Create("assets" + path + "/" + getRandomString(4) + "_" + file.Filename)
	} else {
		dst, err = os.Create("assets" + path + "/" + file.Filename)
	}
	defer dst.Close()
	//fmt.Println(path)
	if err != nil {
		resp := &JsonResp{
			Code: "fileerror",
			Data: "Create file failed.",
		}
		return c.JSON(http.StatusInternalServerError, resp)
	}
	defer dst.Close()
	if _, err = io.Copy(dst, src); err != nil {
		resp := &JsonResp{
			Code: "fileerror",
			Data: "Copy file failed.",
		}
		return c.JSON(http.StatusInternalServerError, resp)
	}
	resp := &JsonResp{
		Code:     "success",
		Data:     "Upload file succeed!",
		Filename: file.Filename,
	}
	return c.JSON(http.StatusOK, resp)
}

func getRandomString(ilen int) string {
	str := "0123456789abcdef"
	bytes := []byte(str)
	result := []byte{}
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < ilen; i++ {
		result = append(result, bytes[r.Intn(len(bytes))])
	}
	return string(result)
}

var gPath string
var html_1_1 = `
<html>
	<head>
		<meta name=viewport content="width=device-width,initial-scale=1">
		<title>小网盘</title>
		<link href="//cdn.jsdelivr.net/npm/bootstrap@3.3.4/dist/css/bootstrap.min.css" rel="stylesheet">
		<link href="//cdn.jsdelivr.net/npm/bootstrap-fileinput@4.4.2/css/fileinput.min.css" media="all" rel="stylesheet" type="text/css" />
		<script src="//cdn.jsdelivr.net/npm/jquery@2.2.2/dist/jquery.min.js"></script>
		<script src="//cdn.jsdelivr.net/npm/bootstrap-fileinput@4.4.2/js/fileinput.min.js"></script>
		<script src="//cdn.jsdelivr.net/npm/bootstrap@3.3.4/dist/js/bootstrap.min.js" type="text/javascript"></script>
		<style type="text/css">
			table tr td:first-child {
				overflow: auto;
				white-space: pre-wrap;
				word-break: break-all;
			}
		</style>
	</head>
	<body> 
	<nav class="navbar navbar-default navbar-fixed-top" style="opacity: .9" role="navigation">
	<div class="container-fluid">
	<div class="navbar-header">
	<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
	<span class="sr-only">Toggle navigation</span>
	<span class="icon-bar"></span>
	<span class="icon-bar"></span>
	<span class="icon-bar"></span>
	</button>
	<a class="navbar-brand" href="#">myHomePage</a>
	</div>
	<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
	<ul class="nav navbar-nav navbar-right">
	<li>
		<div style="margin: 8px;">
		<form class="form-inline" role="form" method="POST" action="/mkdir`
var html_1_2 = `">
		<input type="text" id="filterName" class="form-control" placeholder="过滤关键词">
			<input type="text" class="form-control" id="name" name="dirname" placeholder="文件夹名称">
		<button type="submit" class="btn btn-default">新建</button>
		</form>
		</div>
	</li>

	<li><button class="btn btn-primary btn-md" data-toggle="modal" data-target="#myModal" style="margin: 8px;">
		上传文件
		</button><div></div></li>
	</ul>
	</div>
	</div>
	</nav>
	<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
		<div class="modal-dialog">
			<div class="modal-content">
				<div class="modal-header">
					<button type="button" class="close" data-dismiss="modal" aria-hidden="true">
						&times;
					</button>
					<h4 class="modal-title" id="myModalLabel">
						选择你要上传的文件
					</h4>
				</div>
				<div class="modal-body">
							<input id="smfile" type="file" multiple class="file" data-overwrite-initial="false" data-min-file-count="1" data-max-file-count="10" name="file" accept="*/*">
				</div>
				<div class="modal-footer">
					<button type="button" class="btn btn-default" data-dismiss="modal">关闭
					</button>
				</div>
			</div><!-- /.modal-content -->
		</div><!-- /.modal -->
	</div>
	<div id="filter" class="col-md-10 col-sm-12" style="margin-top: 60px;">
	<table class="table table-hover">
	  <thead>
	    <tr>
	      <th>名称</th>
	      <th>大小</th>
	      <th>预览</th>
	      <th>操作</th>
	    </tr>
	  </thead>
	  <tbody>
`
var html_2 = `	  </tbody>
	</table>
	</body>
			<script type="text/javascript">
			$("#smfile").fileinput({
	            uploadUrl: '`
var html_3 = `',
	            //allowedFileExtensions : ['jpeg', 'jpg', 'png', 'gif', 'bmp'],
	            overwriteInitial: false,
	            maxFileSize: 102400,
	            maxFilesNum: 10,
	            maxFileCount: 10,
	            allowedPreviewTypes: ['image'],
        	});
        	$(".file-drop-zone").css(
        		{
        			"height":"60%",
        		}
        	);
			// NEW selector
			jQuery.expr[':'].Contains = function(a, i, m) {
			  return jQuery(a).text().toUpperCase()
			      .indexOf(m[3].toUpperCase()) >= 0;
			};
			// OVERWRITES old selecor
			jQuery.expr[':'].contains = function(a, i, m) {
			  return jQuery(a).text().toUpperCase()
			      .indexOf(m[3].toUpperCase()) >= 0;
			};
        	function HighLight(){
		       $("#filterName").keyup(function(){
		            if ($(this).val() == "") {
		                $("#filter table tbody tr").show();
		            } else {
		                $("#filter table tbody tr").hide().filter(":contains('"+( $(this).val() )+"')").show();
		            }
		       }).keyup();
		    }
		    $(document).ready(function () {
		        HighLight();
		    });
		</script>
</html>`
